package kom;

import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;

public class Bitmaps {

    private static final int NUMBER_OF_EFFECTS = 2;
    
    public HashMap<Integer, BufferedImage[]> sprites = new HashMap<Integer, BufferedImage[]>();
    public HashMap<Integer, BufferedImage[]> negativeSprites = new HashMap<Integer, BufferedImage[]>();
    public HashMap<Integer, BufferedImage[]> animatedEffects = new HashMap<Integer, BufferedImage[]>();
    public BufferedImage[] iconSet;
    public BufferedImage[][] tiles;

    public int getTileIndex(BlockType b) {
        if (b == BlockType.DIRT) {
            return 1;
        } else if (b == BlockType.AIR) {
            return 2;
        }
        return -1;
    }

    // modifier is the direction of the free block face
    public BufferedImage getTileImage(BlockType b) {
        if (b == BlockType.DIRT) {
            return tiles[0][0];
        }
        if (b == BlockType.AIR) {
            return tiles[0][2];
        }
        if (b == BlockType.STONE) {
            return tiles[0][1];
        }
        return null;
    }

    // modifier is the direction of the free block face
    public BufferedImage getTileImage(BlockType b, int direction) {
        // -- Indexes of the variations of the tile
        //1 = down
        //2 = up
        //3 = right
        //4 = left
        int directionIndex = 1;
        if (direction == Map.DIR_UP) {
            directionIndex = 2;
        } else if (direction == Map.DIR_LEFT) {
            directionIndex = 3;
        }
        if (direction == Map.DIR_RIGHT) {
            directionIndex = 4;
        }

        // gets the variation of that tile
        if (b == BlockType.DIRT) {
            return tiles[directionIndex][0];
        }
        if (b == BlockType.AIR) {
            return tiles[directionIndex][2];
        }
        if (b == BlockType.STONE) {
            return tiles[directionIndex][1];
        }
        return null;
    }

    public void loadAll() throws IOException {
        BufferedImage icons = ImageIO.read(Bitmaps.class.getResourceAsStream("/res/sprites/iconset.png"));
        iconSet = new BufferedImage[icons.getWidth() / 8];
        for (int i = 0; i < icons.getWidth() / 8; i++) {
            iconSet[i] = clip(icons, i * 8, 0, 8, 8);
        }

        BufferedImage src = ImageIO.read(Bitmaps.class.getResourceAsStream("/res/tilesets/tiles.png"));
        tiles = new BufferedImage[src.getWidth() / 8][src.getHeight() / 8];

        // read the tiles, still in simple shape
        for (int i = 0; i < 12; i++) {
            for (int j = 0; j < 4; j++) {
                tiles[i][j] = clip(src, i * 8, j * 8, 8, 8);
            }
        }

        // automatically loading effects
        int i = 0;
        while (i < NUMBER_OF_EFFECTS) {
            BufferedImage effect;
            try {
                // reads from inside the jar so images dont need to be sent separately
                if(Kom.class.getResource("/res/effects/effect" + i + ".png")==null) break;
                effect = ImageIO.read(Kom.class.getResource("/res/effects/effect" + i + ".png"));
                effect = ImageIO.read(Bitmaps.class.getResourceAsStream("/res/effects/effect" + i + ".png"));
            } catch (IOException e) {
                e.printStackTrace(System.out);
                break;
            }
            if (effect == null) {
                break;
            }

            BufferedImage[] effects = new BufferedImage[effect.getWidth() / 16];
            for (int x = 0; x < effect.getWidth() / 16; x++) {
                effects[x] = clip(effect, x * 16, 0, 16, 16);
            }
            animatedEffects.put(i , effects);
            i++;
        }

        // automatically read sprite sheets named "sprites<number>.png" and stores it
        int spriteCounter = 0;
        while (true) {
            BufferedImage chara;
            try {
                // reads from inside the jar so images dont need to be sent separately
                chara = ImageIO.read(Bitmaps.class.getResourceAsStream("/res/sprites/sprites" + spriteCounter + ".png"));
            } catch (Throwable t) {
                break;
            }
            if (chara == null) {
                break;
            }
            BufferedImage[] sprite = new BufferedImage[chara.getWidth() / 16];
            BufferedImage[] negateSprite = new BufferedImage[chara.getWidth() / 16];
            for (int x = 0; x < chara.getWidth() / 16; x++) {
                sprite[x] = clip(chara, x * 16, 0, 16, 20);
                negateSprite[x] = horizontalflip(clip(chara, x * 16, 0, 16, 20));
            }
            sprites.put(spriteCounter, sprite);
            // store the inverse too so we only need to send 1 image to client
            negativeSprites.put(spriteCounter, negateSprite);
            spriteCounter++;
        }
    }

    // flips the image
    public BufferedImage horizontalflip(BufferedImage bufferedImage) {

        AffineTransform tx = AffineTransform.getScaleInstance(-1, 1);
        tx.translate(-bufferedImage.getWidth(null), 0);
        AffineTransformOp op = new AffineTransformOp(tx,
                AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        bufferedImage = op.filter(bufferedImage, null);
        return bufferedImage;

    }

    public static BufferedImage clip(BufferedImage src, int x, int y, int w, int h) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        BufferedImage newImage = null;

        try {
            GraphicsDevice screen = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = screen.getDefaultConfiguration();
            newImage = gc.createCompatibleImage(w, h, Transparency.BITMASK);
        } catch (Exception e) {
        }

        if (newImage == null) {
            newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        }

        int[] pixels = new int[w * h];
        src.getRGB(x, y, w, h, pixels, 0, w);
        newImage.setRGB(0, 0, w, h, pixels, 0, w);

        return newImage;
    }
}